extends CharacterBody2D

## boss的动画
@onready var animationSprtie = $AnimatedSprite2D
## boss的基本状态
@onready var state = $State
## boss的出场音乐
@onready var fight1 = $MusicBox/Fight1
## 攻击音效
@onready var attack1 = $MusicBox/Attack1
## boss的聊天框
@onready var label = $TalkLabel
## 工具类
@onready var util = Util.new()
## 录制图标
@onready var rec = $"../REC"
## 烟花攻击特效
@onready var fireWorks = load("res://Boss/Mettaton/tscn/FireWorks.tscn")
## boss的眼睛(玩家检测碰撞箱)
@onready var eyes = $Eyes

## 摄像头
var camera = null
var shakeTime = 0
const shakeTimeAdd = 0.5
const freq = 0.02
const shakeRange = 20
const shakeLength = 10

## 玩家对象
var body = null

## boss的活动事件
var activeStep = -1

## boss的聊天事件
var chatStep = 0

## boss要前往的目标坐标
var targetPosition

## 只有通过作弊才能杀死boss
## 这个时候就可以输出一段话嘲讽玩家是个可悲的作弊玩家
var isDeath = false

## 美塔顿初始化序列标志
var activeInit = null

## _process执行的时间
var time = 0.0

## 用于统计某些事件发生的次数
var count = 0

## 记录谈话是否结束
var talkIsComplete = false

## 子弹池(先预创建1000个子弹,之后每次的子弹使用都从这获取, 不用再创建)
## 子弹使用到期后, 将子弹归还到这个集合中
static var fireWorksPool = []

func _ready():
	# 获取摄像头
	camera = util.findOne("![Camera2D]", self)
	# 初始化数据
	self.activeInit = util.initArray(30, false)
	# 默认播放hello动画
	animationSprtie.play("hello")
	# 绑定事件
	eyes.connect("body_entered", bodyEntered)
	eyes.connect("body_exited", bodyExited)
	state.connect("death", death)
	state.connect("hurt", hurt)
	label.connect("chatComplete", chatComplete)
	# 创建子弹池
	initFireWorksPool(450)
	
	
func initFireWorksPool(num):
	for _index in num:
		initFirework()
	
	
func initFirework():
	var item = fireWorks.instantiate()
	item.global_position = Vector2(-30, -30)
	# 连接回收事件
	item.hide()
	item.connect("recycle", fireworksRecycle)
	fireWorksPool.append(item)
	get_tree().root.add_child(item)
	
## 子弹回收事件被触发调用
## @Param node 子弹对象
func fireworksRecycle(node):
	if not fireWorksPool.has(node):
		print("当前子弹库存", len(fireWorksPool))
		# 将子弹归还
		node.global_position = Vector2(-30, -30)
		node.hide()
		fireWorksPool.append(node)
	
	
func bodyEntered(body):
	self.body = body
	
	
func bodyExited(body):
	if self.body == body:
		body = null
	print("玩家死了")
	
	
## 受伤事件
## 只用来开始游戏
func hurt(_x):
	if activeStep == -1:
		activeStep = 0
		
		
func _process(delta):
	match activeStep:
		# boss被首次被击中, 播放动画以及嘲笑玩家
		0:
			if !activeInit[0]:
				activeInit[0] = true
				talkIsComplete = false
				# 切换为生气动画
				animationSprtie.play("angry")
				label.addChat("可笑的攻击", 0.05, 0.3)
				
			if talkIsComplete:
				next()
				
		1:
			if !activeInit[1]:
				activeInit[1] = true
				talkIsComplete = false
				# 播放攻击音乐1(阶段1)
				fight1.play()
				# 隐藏地图, 后播放黑白talk动画
				util.findOne("$[Sprite2D]", get_parent()).visible = false
				animationSprtie.play("talk2")
				label.addChat(["接招吧", "你会在痛苦中死去"], 0.05, 0.2)
				# 开启录制图标
				rec.isActive = true
				
			if talkIsComplete:
				next()
				
		2:
			# 阶段初始化
			if !activeInit[2]:
				targetPosition = Vector2(position.x, position.y - 60)
				animationSprtie.play("fly2")
				activeInit[2] = true
				print("Mettaton 切换飞行模式")
			
			# boss移动
			if bossMove(targetPosition, 80, delta):
				next()
				
		# 三角直线射击
		3:
			time += delta
			# 初始化, 只执行一次
			if !activeInit[3]:
				shakeTime = 0
				shakeCamera()
				attack1.play()
				time = 0.0
				activeInit[3] = true
				var config = [
					{"func": func(i): return Vector2(1, 1) * i},
					{"func": func(i): return Vector2(1, 0) * i},
					{"func": func(i): return Vector2(0, 1) * i}
				]
				createFireWorkByConfig(config)
				
			if time >= 1:
				next()
		
		# 三角直线射击
		4:
			time += delta
			# 初始化, 只执行一次
			if !activeInit[4]:
				shakeTime = 0
				shakeCamera()
				attack1.play()
				time = 0.0
				activeInit[4] = true
				var config = [
					{"func": func(i): return Vector2(-1, 1) * i},
					{"func": func(i): return Vector2(-1, 0) * i},
					{"func": func(i): return Vector2(0, 1) * i}
				]
				createFireWorkByConfig(config)
			
			if time >= 1:
				next()
		
		# 圆环弹幕
		5:
			time += delta
			if !activeInit[5]:
				time = 0.0
				activeInit[5] = true
				var config = [
					{"num": 10, "speed": 50}
				]
				drawCircleByConfig(config)
			
			if time >= 1:
				next()
				
		6:
			time += delta
			if !activeInit[6]:
				time = 0.0
				activeInit[6] = true
				var config = [
					{"num": 10, "speed": 50},
					{"num": 20, "speed": 100}
				]
				drawCircleByConfig(config)
			
			if time >= 1:
				next()
				
		7:
			time += delta
			if !activeInit[7]:
				time = 0.0
				activeInit[7] = true
				var config = [
					{"num": 10, "speed": 50},
					{"num": 20, "speed": 100},
					{"num": 30, "speed": 200}
				]
				drawCircleByConfig(config)
			
			if time >= 1:
				next()
		
		# 移动攻击
		8:
			time += delta
			if !activeInit[8]:
				time = 0.0
				targetPosition = Vector2(position.x - 200, position.y)
				animationSprtie.rotation = -PI / 2
				activeInit[8] = true
				
			if time >= 0.8:
				var config = [
					{"num": 30, "speed": 50}
				]
				drawCircleByConfig(config)
				time = 0.0
				
			# boss移动
			if bossMove(targetPosition, 20, delta):
				animationSprtie.rotation = 0
				next()
				
		# 休息模式
		9:
			time += delta
			if !activeInit[9]:
				time = 0.0
				activeInit[9] = true
				label.addChat(["为什么你还活着?", "接下来如何呢?"], 0.1, 0.3)
			
			# 倒计时5秒后, 进行下一个阶段
			if time >= 5:
				next()
				
		# 疯狗模式, 追着玩家啃
		10:
			time += delta
			if !activeInit[10]:
				count = 0
				time = 0.0
				shakeTime = 0
				activeInit[10] = true
			
			# 每隔一秒攻击一次
			if time >= 1 && body != null:
				count += 1
				shakeTime = 0
				attack1.play()
				shakeCamera()
				var targetPosition: Vector2 = body.global_position - global_position
				targetPosition = targetPosition.normalized()
				var config = [
					{
						"func": func(i): return targetPosition * i, 
						"speed": 100
					}
				]
				createFireWorkByConfig(config)
				time = 0.0
			
			# 当攻击次数到达5次或以上, 切换模式
			if count >= 5:
				next()
				
		11:
			time += delta
			if !activeInit[11]:
				time = 0.0
				talkIsComplete = false
				label.addChat(["你居然活下来了!", "我承认你比我想得还要强大", "但接下来没人可以活下来!!!!"], 0.1, 0.3)
				activeInit[11] = true
				
			if time >= 0.8:
				time = 0.0
				var config = [
					{"num": 10, "speed": 30}
				]
				drawCircleByConfig(config)
			
			if talkIsComplete:
				next()
				
		12:
			time += delta
			if !activeInit[12]:
				time = 0.0
				activeInit[12] = true
				
			if time >= 0.8:
				time = 0.0
				var config = [
					{"num": 50, "speed": 10},
					{"num": 50, "speed": 20},
					{"num": 50, "speed": 40},
					{"num": 50, "speed": 80},
					{"num": 50, "speed": 160}
				]
				drawCircleByConfig(config)
				next()
			
		13:
			time += delta
			if !activeInit[13]:
				time = 0.0
				shakeTime = 0
				count = 0
				activeInit[13] = true
				
			if time >= 2 && body != null:
				shakeTime = 0
				attack1.play()
				shakeCamera()
				
				# 目标向量
				var targetPosition = (body.global_position - global_position).normalized()
				var leftPos = (targetPosition + targetPosition.rotated(deg_to_rad(30))).normalized()
				var rightPos = (targetPosition + targetPosition.rotated(deg_to_rad(-30))).normalized()
				
				var config = [
					{
						"func": func(i): return targetPosition * i,
						"speed": 100
					},
					{
						"func": func(i): return leftPos * i,
						"speed": 100
					},
					{
						"func": func(i): return rightPos * i,
						"speed": 100
					}
				]
				createFireWorkByConfig(config)
				time = 0.0
			
			# 当攻击次数到达5次或以上, 切换模式
			#if count >= 5:
				#next()
			
## boss移动函数
## @param targetPosition 目标坐标
## @param speed 移动速度
func bossMove(targetPosition: Vector2, speed: int, delta) -> bool:
	var movePosition = (targetPosition - position).normalized()
	velocity = velocity.move_toward(movePosition * speed, 1000 * delta)
	move_and_collide(velocity * delta)
	
	# 判断是否移动到位, 允许出现正负2的误差
	if abs(position.x - targetPosition.x) <= 2 && abs(position.y - targetPosition.y) <= 2:
		return true
	
	return false
	
	
	# 检测到玩家杀死boss
	# 这件事是不可能发生的, 除非玩家改数据
	if self.isDeath:
		self.queue_free()
		
		
## 对话结束(不触发事件推进)
func chatComplete():
	# 等待1秒
	await get_tree().create_timer(1).timeout
	# 隐藏对话框并将标记为说话完成
	label.visible = false
	talkIsComplete = true
	
	
	
## 死亡事件
func death():
	if !self.isDeath:
		self.isDeath = true
		label.addChat(["可悲的黑客", "真可恶!!!!!"], 0.1, 0.5, false)
		
		
func attack():
	print("Mettaton Attacking")
	
	
	
## 创建firework弹幕
## @param direction 方向
## @param speed 子弹速度
func createFirework(direction, speed):
	# 从池中直接拿取对象使用, 这样避免频繁创建
	var item = fireWorksPool.pop_front()
	# 应用子弹相关脚本
	item.applyFirewrok()
	item.position = self.global_position
	item.direction = direction
	item.speed = speed
	item.show()
	
## 通过配置批量创建firework
## @param config 配置项
func createFireWorkByConfig(config):
	print("批量创建弹幕", config)
	for item in config:
		var number = null
		var speed = null
			
		if !item.has("num"):
			number = 10
		else:
			number = item.num
			
		if item.has("speed"):
			speed = item.speed
			
		for value in range(1, number):
			createFirework(item["func"].call(value), speed)
			
			
## 绘制圆形弹幕
## @param num 组成圆形的数量
## @param speed 扩散速度
func drawCirlce(num, speed):
	var angleStep = TAU / num
	for i in range(num):
		var angle = angleStep * i
		createFirework(Vector2.from_angle(angle), speed)
		
		
## 通过配置批量绘制圆形
## @param config 配置
func drawCircleByConfig(config):
	print("批量绘制圆环弹幕", config)
	for item in config:
		var num = item.num
		var speed = 100
			
		if item.has("speed"):
			speed = item.speed
			
		drawCirlce(num, speed)
		
		
## 镜头摇晃
func shakeCamera():
	var camera_position = camera.position
	while shakeTime < shakeLength:
		shakeTime += shakeTimeAdd
		# 随机摇晃
		var new_position = camera_position
		
		# 随机摇晃
		new_position += Vector2(randf_range(-shakeRange, shakeRange),
								randf_range(-shakeRange, shakeRange))
		
		camera.position = new_position
		# 使用 await 代替 yield
		await get_tree().create_timer(freq).timeout
		
	# 恢复原始位置
	camera.position = camera_position
	
	
## 游戏进度+=1
func next():
	activeStep += 1
